//! 扩展管理器 (ExtensionManager) - 内核的总调度师
//!
//! 对应 `ai-server` 的 `services/extension_manager.py`。

use std::any::Any;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex};

use crate::core::beans::bean::{Bean, BeanManager, IDestructible};
use crate::core::beans::constants::expansion_feature_names;
use crate::core::manifest::{ActivationEvent, ExpansionManifest};
use crate::core::plugin::RigPlugin;

use crate::core::services::context_manager::ContextManager;
use crate::core::services::contribution_keyword_manager::ContributionKeywordManager;
use crate::core::services::event_manager::{expansion_lifecycle_event_names, EventManager};
use crate::core::services::manifest_manager::ManifestManager;
use crate::core::services::protocols::IContributionKeyword;

fn expr_is_boolean(when: &Option<String>) -> bool {
    if when.is_none() {
        return true;
    }
    true
}

/// 扩展管理器
pub struct ExtensionManager {
    manifest_manager: Arc<ManifestManager>,
    context_manager: Arc<ContextManager>,
    event_manager: Arc<EventManager>,
    contribution_manager: Arc<ContributionKeywordManager>,

    impls: Mutex<HashMap<String, Arc<Mutex<Box<dyn RigPlugin>>>>>,
    apis: Mutex<HashMap<String, Arc<dyn Any + Send + Sync>>>,
    activated: Mutex<HashMap<String, bool>>,
    activated_events: Mutex<Vec<String>>,
}

impl IDestructible for ExtensionManager {
    fn destructor(&self) {
        self.impls.lock().unwrap().clear();
        self.apis.lock().unwrap().clear();
        self.activated.lock().unwrap().clear();
        println!("ExtensionManager destroyed.");
    }
}

impl Bean for ExtensionManager {
    fn new(bean_manager: &Arc<BeanManager>) -> Arc<Self> {
        Arc::new(Self {
            manifest_manager: bean_manager.get_bean(expansion_feature_names::MANIFEST_MANAGER).unwrap(),
            context_manager: bean_manager.get_bean(expansion_feature_names::CONTEXT_MANAGER).unwrap(),
            event_manager: bean_manager.get_bean(expansion_feature_names::EVENT_MANAGER).unwrap(),
            contribution_manager: bean_manager.get_bean(expansion_feature_names::CONTRIBUTION_KEYWORD_MANAGER).unwrap(),
            impls: Mutex::new(HashMap::new()),
            apis: Mutex::new(HashMap::new()),
            activated: Mutex::new(HashMap::new()),
            activated_events: Mutex::new(Vec::new()),
        })
    }
}

impl ExtensionManager {
    pub async fn activate(&self, activation_event: &str, repeat: bool) {
        let mut activated_events = self.activated_events.lock().unwrap();
        if !repeat && activated_events.contains(&activation_event.to_string()) {
            return;
        }

        if !repeat {
            activated_events.push(activation_event.to_string());
        }

        let manifests_to_activate = self.get_manifests_by_activation_event(activation_event);

        if manifests_to_activate.is_empty() {
            return;
        }

        self.install_extensions(manifests_to_activate).await;
    }

    pub async fn deactivate(&self, activation_event: &str) {
        let mut activated_events = self.activated_events.lock().unwrap();
        if activated_events.last() != Some(&activation_event.to_string()) {
            return;
        }

        activated_events.pop();

        let manifests_to_deactivate = self.get_manifests_by_deactivation_event(activation_event);
        if manifests_to_deactivate.is_empty() {
            return;
        }

        self.uninstall_extensions(manifests_to_deactivate).await;
    }

    async fn install_extensions(&self, manifests: Vec<ExpansionManifest>) {
        let waterfalls = self.analysis_activate_waterfall(manifests.clone());

        for batch in waterfalls {
            for name in batch {
                if let Some(manifest) = self.manifest_manager.get_manifest(&name) {
                    self.internal_activate(manifest).await;
                }
            }
        }

        for manifest in manifests {
            let name = &manifest.name;
            let impls = self.impls.lock().unwrap();
            if let Some(plugin_impl) = impls.get(name) {
                let ctx = self.context_manager.get_activate_context(name);
                plugin_impl.lock().unwrap().post_activated(&ctx);
            }
        }
    }

    async fn uninstall_extensions(&self, manifests: Vec<ExpansionManifest>) {
        for manifest in manifests {
            self.internal_deactivate(&manifest).await;
        }
    }

    fn get_manifests_by_activation_event(&self, name: &str) -> Vec<ExpansionManifest> {
        self.manifest_manager
            .get_should_activates(name)
            .into_iter()
            .filter_map(|(manifest, event)| {
                let when = match event {
                    ActivationEvent::Conditional(s) => s.when,
                    _ => None,
                };
                if expr_is_boolean(&when) {
                    Some(manifest)
                } else {
                    None
                }
            })
            .collect()
    }

    fn get_manifests_by_deactivation_event(&self, name: &str) -> Vec<ExpansionManifest> {
        let activated = self.activated.lock().unwrap();
        self.manifest_manager
            .get_should_deactivates(name)
            .into_iter()
            .filter(|m| activated.get(&m.name).cloned().unwrap_or(false))
            .collect()
    }

    async fn internal_activate(&self, manifest: ExpansionManifest) {
        let name = manifest.name.clone();
        if self.activated.lock().unwrap().get(&name).cloned().unwrap_or(false) {
            return;
        }

        let plugin_impl = self._load_impl(&manifest);
        self.impls.lock().unwrap().insert(name.clone(), plugin_impl.clone());

        let ctx = self.context_manager.get_activate_context(&name);
        ctx.set_stage("beforeActivate");

        plugin_impl.lock().unwrap().before_activate(&ctx);
        self.event_manager.dispatch(expansion_lifecycle_event_names::BEFORE_EXTENSION_ACTIVATE, Arc::new(name.clone()));

        if let Some(keywords) = &manifest.contribution_keywords {
            for keyword_def in keywords {
                if let Some(keyword_impl_any) = plugin_impl.lock().unwrap().get_contribution_keyword(keyword_def, &ctx) {
                    if let Some(keyword_impl_arc) = keyword_impl_any.downcast_ref::<Arc<dyn IContributionKeyword>>() {
                        self.contribution_manager.implement_contribution_keyword(&keyword_def.name, keyword_impl_arc.clone());
                    }
                }
            }
        }

        ctx.set_stage("activate");
        if let Some(api) = plugin_impl.lock().unwrap().activate(&ctx).await {
            self.apis.lock().unwrap().insert(name.clone(), api);
        }

        self.activated.lock().unwrap().insert(name.clone(), true);
        self.event_manager.dispatch(expansion_lifecycle_event_names::ON_EXTENSION_ACTIVATED, Arc::new(name.clone()));
    }

    async fn internal_deactivate(&self, manifest: &ExpansionManifest) {
        let name = &manifest.name;
        if !self.activated.lock().unwrap().get(name).cloned().unwrap_or(false) {
            return;
        }

        self.event_manager.dispatch(expansion_lifecycle_event_names::BEFORE_EXTENSION_DEACTIVATE, Arc::new(name.clone()));

        let ctx = self.context_manager.get_activate_context(name);
        if let Some(plugin_impl) = self.impls.lock().unwrap().get(name) {
            plugin_impl.lock().unwrap().deactivate(&ctx).await;
        }

        self.activated.lock().unwrap().insert(name.clone(), false);
        self.event_manager.dispatch(expansion_lifecycle_event_names::ON_EXTENSION_DEACTIVATED, Arc::new(name.clone()));

        self.apis.lock().unwrap().remove(name);
        self.impls.lock().unwrap().remove(name);
        self.context_manager.destroy_activate_context(name);
    }

    fn _load_impl(&self, manifest: &ExpansionManifest) -> Arc<Mutex<Box<dyn RigPlugin>>> {
        Arc::new(Mutex::new((manifest.implementation)()))
    }

    pub fn get_api(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>> {
        self.apis.lock().unwrap().get(name).cloned()
    }

    pub fn get_context(&self, manifest: &ExpansionManifest, _contributor: &str) -> Option<Arc<dyn Any + Send + Sync>> {
        if let Some(plugin_impl) = self.impls.lock().unwrap().get(&manifest.name) {
            return plugin_impl.lock().unwrap().get_context();
        }
        None
    }

    fn analysis_activate_waterfall(&self, manifests: Vec<ExpansionManifest>) -> Vec<Vec<String>> {
        let mut in_degree: HashMap<String, usize> = HashMap::new();
        let mut adj: HashMap<String, Vec<String>> = HashMap::new();
        let activated_plugins = self.activated.lock().unwrap();

        let manifest_names: Vec<String> = manifests.iter().map(|m| m.name.clone()).collect();

        for manifest in &manifests {
            let name = &manifest.name;
            in_degree.entry(name.clone()).or_insert(0);
            adj.entry(name.clone()).or_insert_with(Vec::new);

            if let Some(deps) = &manifest.dependencies {
                for dep_name in deps.keys() {
                    if manifest_names.contains(dep_name) && !activated_plugins.get(dep_name).cloned().unwrap_or(false) {
                        in_degree.entry(name.clone()).and_modify(|e| *e += 1);
                        adj.entry(dep_name.clone()).or_insert_with(Vec::new).push(name.clone());
                    }
                }
            }
        }

        let mut queue: VecDeque<String> = VecDeque::new();
        for name in &manifest_names {
            if in_degree.get(name).cloned().unwrap_or(0) == 0 {
                queue.push_back(name.clone());
            }
        }

        let mut result: Vec<Vec<String>> = Vec::new();
        while !queue.is_empty() {
            let mut current_level = vec![];
            let level_size = queue.len();
            for _ in 0..level_size {
                if let Some(u) = queue.pop_front() {
                    current_level.push(u.clone());
                    if let Some(neighbors) = adj.get(&u) {
                        for v in neighbors {
                            if let Some(degree) = in_degree.get_mut(v) {
                                *degree -= 1;
                                if *degree == 0 {
                                    queue.push_back(v.clone());
                                }
                            }
                        }
                    }
                }
            }
            result.push(current_level);
        }

        if result.iter().flatten().count() != manifest_names.len() {
            panic!("Circular dependency detected");
        }

        result
    }
}